﻿using Bling.DSL;
using Bling.Core;
using Bling.Util;
using System.Collections.Generic;
using System;
using linq = Microsoft.Linq.Expressions;

namespace Bling.Core {
  public interface IDim { }
  public interface IDim<DIM> : IDim where DIM : IDim<DIM> { }

  public abstract class Dim {
    public abstract int CountI { get; }
    public abstract string NameI { get; }

    public static Dim InstanceFor(Type t) {
      var DimT = typeof(Dim<>).MakeGenericType(t);
      var Fld = DimT.GetField("Instance");
      return (Dim) Fld.GetValue(null);
    }
  }
  public abstract class Dim<DIM> : Dim, IDim<DIM> where DIM : Dim<DIM> {
    protected Dim() { }
    public static readonly DIM Instance;
    static Dim() {
      Instance = (DIM)typeof(DIM).GetConstructor(new Type[0]).Invoke(new object[0]);
      (Instance != null).Assert();
    }
    public static int Count { get { return Instance.CountI; } }
    public static string Name { get { return Instance.NameI; } }
  }
  public interface INextDim<DIM, NEXT>
    where DIM : IDim1D<DIM>, INextDim<DIM, NEXT>
    where NEXT : IDim1D<NEXT>, IPrevDim<NEXT, DIM> { }

  public interface IPrevDim<DIM, PREV> : IDim<IPrevDim<DIM,PREV>>
    where DIM : IDim1D<DIM>, IPrevDim<DIM, PREV>
    where PREV : IDim1D<PREV>, INextDim<PREV, DIM> { }
  public interface IDim1D : IDim { }
  public interface IDim1D<D> : IDim<D>, IDim1D where D : IDim1D<D> { }

  public interface IDim2D : IDim {
    int RowCountI { get; }
    int ColCountI { get; }
  }
  public interface IDim2D<D> : IDim<D>, IDim2D where D : IDim2D<D> {}

  public abstract class Dim2D<SELF> : Dim<SELF>, IDim2D<SELF> where SELF : Dim2D<SELF> {
    public static int RowCount { get { return Instance.RowCountI; } }
    public static int ColCount { get { return Instance.ColCountI; } }
    public abstract int RowCountI { get; }
    public abstract int ColCountI { get; }
  }
  public class Dim<ROW, COL> : Dim2D<Dim<ROW, COL>>
    where ROW : Dim1D<ROW>
    where COL : Dim1D<COL> {
    public override int RowCountI { get { return Dim1D<ROW>.Count; } }
    public override int ColCountI { get { return Dim1D<COL>.Count; } }
    public override int CountI { get { return RowCountI * ColCountI; } }
    public override string NameI {
      get { return "M" + RowCountI + "x" + ColCountI; }
    }
  }

  public abstract class Dim1D<D> : Dim<D>, IDim1D<D> where D : Dim1D<D> {
    public override string NameI {
      get { return "V" + CountI; }
    }
  }
  public abstract class Dim1D<D, P, N> : Dim1D<D>, IPrevDim<D, P>, INextDim<D, N>
    where D : Dim1D<D, P, N>
    where P : Dim1D<P>, INextDim<P, D>
    where N : Dim1D<N>, IPrevDim<N, D> {
  }
  public interface ICoreDim1D<D> where D : Dim1D<D>, ICoreDim1D<D> { }

  public abstract class CoreDim1D<D, P, N> : Dim1D<D, P, N>, ICoreDim1D<D>
    where D : CoreDim1D<D, P, N>
    where P : Dim1D<P>, INextDim<P, D>
    where N : Dim1D<N>, IPrevDim<N, D> {
  }
  public interface IMultiDim1D<D> : ICoreDim1D<D> where D : Dim1D<D>, IMultiDim1D<D> { }
  public abstract class MultiDim1D<D, P, N> : CoreDim1D<D, P, N>, IMultiDim1D<D>
    where D : MultiDim1D<D, P, N>
    where P : Dim1D<P>, INextDim<P, D>
    where N : Dim1D<N>, IPrevDim<N, D> {
  }


  public class D0 : Dim1D<D0>, INextDim<D0, D1> {public override int CountI {get{return 0;}}}
  public class D1 : CoreDim1D<D1, D0, D2> { public override int CountI { get { return 1; } } }
  public class D2 : MultiDim1D<D2, D1, D3> { public override int CountI { get { return 2; } } }
  public class D3 : MultiDim1D<D3, D2, D4> { public override int CountI { get { return 3; } } }
  public class D4 : MultiDim1D<D4, D3, D5> { public override int CountI { get { return 4; } } }
  public class D5 : Dim1D<D5, D4, D6> { public override int CountI { get { return 5; } } }
  public class D6 : Dim1D<D6, D5, D7> { public override int CountI { get { return 6; } } }
  public class D7 : Dim1D<D7, D6, D8> { public override int CountI { get { return 7; } } }
  public class D8 : Dim1D<D8, D7, D9> { public override int CountI { get { return 8; } } }
  public class D9 : Dim1D<D9, D8, D10> { public override int CountI { get { return 9; } } }
  public class D10 : Dim1D<D10, D9, D11> { public override int CountI { get { return 10; } } }
  public class D11 : Dim1D<D11, D10, D12> { public override int CountI { get { return 11; } } }
  public class D12 : Dim1D<D12, D11, D13> { public override int CountI { get { return 12; } } }
  public class D13 : Dim1D<D13, D12, D14> { public override int CountI { get { return 13; } } }
  public class D14 : Dim1D<D14, D13, D15> { public override int CountI { get { return 14; } } }
  public class D15 : Dim1D<D15, D14, D16> { public override int CountI { get { return 15; } } }
  public class D16 : Dim1D<D16>, IPrevDim<D16, D15> { public override int CountI { get { return 16; } } }

  public static class Dims {
    internal static readonly Type[] Elements = new Type[] {
      typeof(D0),
      typeof(D1),
      typeof(D2),
      typeof(D3),
      typeof(D4),
      typeof(D5),
      typeof(D6),
      typeof(D7),
      typeof(D8),
      typeof(D9),
      typeof(D10),
      typeof(D11),
      typeof(D12),
      typeof(D13),
      typeof(D14),
      typeof(D15),
      typeof(D16),
    };
    private static readonly Dictionary<Type, int> Counts = new Dictionary<Type, int>();
    public static int CountFor(Type t) {
      return Counts[t];
    }
    static Dims() {
      for (int i = 0; i < Elements.Length; i++) {
        (Elements[i] != null).Assert();
        Counts[Elements[i]] = i;
      }
    }
  }

  // get rid of arity constructs.
}
namespace Bling.Vecs {

  public static class VecExtensions {
    public static T[] Values<T, D>(this IVec<T, D> vec) where D : Dim<D> {
      var ret = new T[Dim<D>.Count];
      for (int i = 0; i < ret.Length; i++) ret[i] = vec[i];
      return ret;
    }

  }

  public static partial class VecUtils {
    public static string ToString<T, D>(IVec<T, D> v) where D : Dim<D> {
      string s = "[";
      for (int i = 0; i < Dim<D>.Count; i++) {
        var sep = "";
        if (i > 0) sep = ", ";

        s += sep + v[i];
      }
      return s + "]";
    }
  }
  public interface IVec { 
    object BaseGet(int Idx);
  }
  public interface IVec<T> : IVec {
    T this[int Idx] { get; }
  }
  public interface IVec<T, D> : IVec<T> where D : Dim<D> { }
  public static partial class VecUtils {
    public static T Access<T, D>(this IVec<T, D> vec, int m, int n) where D : Dim2D<D> {
      return vec[m * Dim2D<D>.ColCount + n];
    }
  }
}
namespace Bling.Vecs { // default implementations. 

  public static partial class VecUtils {
    public static readonly Type[] Elements = new Type[] {
      typeof(Vec0<>),
      typeof(Vec1<>),
      typeof(Vec2<>),
      typeof(Vec3<>),
      typeof(Vec4<>),
      typeof(Vec5<>),
      typeof(Vec6<>),
      typeof(Vec7<>),
      typeof(Vec8<>),
      typeof(Vec9<>),
      typeof(Vec10<>),
      typeof(Vec11<>),
      typeof(Vec12<>),
      typeof(Vec13<>),
      typeof(Vec14<>),
      typeof(Vec15<>),
      typeof(Vec16<>),
    };
    private static readonly Dictionary<Type, Type> Mapping = new Dictionary<Type, Type>();
    static VecUtils() {
      for (int i = 0; i < Dims.Elements.Length; i++) {
        (Dims.Elements[i] != null).Assert();
        (Elements[i] != null).Assert();
        Mapping[Dims.Elements[i]] = Elements[i];
      }
    }
    public class Info {
      public Type Original;
      public Type ToType;
      public Dim Dim;
      public Type TypeOfK;

      public int Count { get { return Dim.CountI; } }

      public Func<linq.Expression,linq.Expression> PropertyFor(int Idx) {
        if (Dim == D1.Instance) return e => e;
        return e => linq.Expression.Field(e, "_" + Idx);
      }

      public IVec Create(object[] Values) {
        (Values.Length == Dim.CountI).Assert();
        if (!Creates.ContainsKey(Original)) {
          var assigns = new linq.Expression[Dim.CountI + 2];
          var param = new linq.ParameterExpression[] { linq.Expression.Parameter(ToType, "param") };
          var array = linq.Expression.Parameter(ToType.GetGenericArguments()[0].MakeArrayType(), "args");
          assigns[0] = linq.Expression.Assign(param[0], linq.Expression.New(ToType));
          for (int i = 0; i < Dim.CountI; i++) {
            assigns[i + 1] = linq.Expression.Assign(
              linq.Expression.Field(param[0], "_" + i),
              linq.Expression.ArrayAccess(array, linq.Expression.Constant(i, typeof(int))));
          }
          assigns[Dim.CountI + 1] = linq.Expression.Convert(param[0], Original);
          var block = linq.Expression.Block(Original, param, assigns);
          var lambda = linq.Expression.Lambda(block, array);
          Creates[Original] = lambda.Compile();
        }
        throw new NotSupportedException();
        //return ((System.Func<T[], IVec<T, D>>)Creates[typeof(IVec<T, D>)])(Values);

      }
    }

    public static Info Query(Type T) {
      if (T.IsGenericType && T.GetGenericTypeDefinition() == typeof(IVec<,>)) {
        var K = T.GetGenericArguments()[0];
        var D = T.GetGenericArguments()[1];
        var DimI = Dim.InstanceFor(D);
        var ToType = Transform(K, D);
        return new Info() {
          ToType = ToType,
          Dim = DimI,
          Original = T,
          TypeOfK = K,
        };
      } else {

        return new Info() {
          ToType = T,
          Dim = D1.Instance,
          Original = T,
          TypeOfK = T,
        };

      }
      return null;
    }

    public static Type Transform(Type T, Type D) {
      return Transform(T, D, false);
    }
    public static Type Transform(Type T, Type D, bool DoD1) {
      if (D == typeof(D1) && !DoD1) {
        return T;
      }
      if (Mapping.ContainsKey(D)) return Mapping[D].MakeGenericType(T);
      // must be a Dim<,>
      var E = D;
      while (!E.IsGenericType || E.GetGenericTypeDefinition() != typeof(Dim<,>))
        E = E.BaseType;
      // we've got two dimensions
      var DA = E.GetGenericArguments()[0];
      var DB = E.GetGenericArguments()[1];
      var cnt = Dims.CountFor(DA) * Dims.CountFor(DB);
      var S = Elements[cnt];
      Mapping[D] = S;
      return S.MakeGenericType(T);
    }
    private static readonly Dictionary<Type, object> Creates = new Dictionary<Type, object>();


    public static IVec<T, D> Create<T, D>(T[] Values) where D : Dim<D> {
      (Values.Length == Dim<D>.Count).Assert();
      if (!Creates.ContainsKey(typeof(IVec<T, D>))) {
        var ToT = Transform(typeof(T), typeof(D), true);
        var assigns = new linq.Expression[Dim<D>.Count + 2];
        var param = new linq.ParameterExpression[] { linq.Expression.Parameter(ToT, "param") };
        var array = linq.Expression.Parameter(typeof(T[]), "args");
        assigns[0] = linq.Expression.Assign(param[0], linq.Expression.New(ToT));
        for (int i = 0; i < Dim<D>.Count; i++) {
          assigns[i + 1] = linq.Expression.Assign(
            linq.Expression.Field(param[0], "_" + i),
            linq.Expression.ArrayAccess(array, linq.Expression.Constant(i, typeof(int))));
        }
        assigns[Dim<D>.Count + 1] = linq.Expression.Convert(param[0], typeof(IVec<T,D>));
        var block = linq.Expression.Block(typeof(IVec<T,D>), param, assigns);
        var lambda = linq.Expression.Lambda<System.Func<T[], IVec<T, D>>>(block, array);
        Creates[typeof(IVec<T, D>)] = lambda.Compile();
      }
      return ((System.Func<T[], IVec<T, D>>)Creates[typeof(IVec<T, D>)])(Values);
    }
    private static readonly Dictionary<Type, IVec> Defaults = new Dictionary<Type, IVec>();

    public static T DefaultFor<T>() {
      if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(IVec<,>)) return (T) DefaultFor(typeof(T));
      return default(T);
    }

    public static IVec DefaultFor(Type TT) {
      if (Defaults.ContainsKey(TT)) return Defaults[TT];
      var K = TT.GetGenericArguments()[0];
      var D = TT.GetGenericArguments()[1];
      var ToType = Transform(K, D, true);
      var DimI = Dim.InstanceFor(D);

      var assigns = new linq.Expression[DimI.CountI + 2];
      var param = linq.Expression.Parameter(ToType, "Default");
      assigns[0] = linq.Expression.Assign(param, linq.Expression.New(ToType));
      linq.Expression RHS = linq.Expression.Default(K);

      for (int i = 0; i < DimI.CountI; i++) {
        assigns[i + 1] = linq.Expression.Assign(
          linq.Expression.Field(param, "_" + i), RHS);

      }
      assigns[DimI.CountI + 1] = linq.Expression.Convert(param, TT);
      var block = linq.Expression.Block(typeof(IVec), new linq.ParameterExpression[] { param }, assigns);

      var instance = linq.Expression.Lambda<System.Func<IVec>>(block).Compile()();

      Defaults[TT] = instance;
      return instance;
    }
    public static Type TransformType(Type T) {
      if (T.IsArray) {
        var E = TransformType(T.GetElementType());
        var rank = T.GetArrayRank();
        return rank == 1 ? E.MakeArrayType() : E.MakeArrayType(rank);
      } else if (T.IsGenericType && T.GetGenericTypeDefinition() == typeof(IVec<,>)) {
        return VecUtils.Transform((T.GetGenericArguments()[0]), T.GetGenericArguments()[1]);
      } else if (T.IsGenericType && false) {
        var Ts = new Type[T.GetGenericArguments().Length];
        for (int i = 0; i < Ts.Length; i++)
          Ts[i] = TransformType(T.GetGenericArguments()[i]);
        return T.GetGenericTypeDefinition().MakeGenericType(Ts);
      }
      return T;
    }
    public static Expr Transform(Expr e, Type ToType) {
      if (e.TypeOfT == ToType) return e;
      (TransformType(ToType) == e.TypeOfT).Assert();

      if (ToType.IsGenericType && ToType.GetGenericTypeDefinition() == typeof(IVec<,>)) {
        var S = ToType.GetGenericArguments()[0];
        var D = ToType.GetGenericArguments()[1];
        if (D == typeof(D1)) {
          (S == e.TypeOfT).Assert();
          var D1Convert = typeof(Ops.D1Convert<>).MakeGenericType(S);
          var mthd = D1Convert.GetMethod("DoToVec");
          (mthd != null).Assert();
          return (Expr) mthd.Invoke(null, new object[] { e });
        } else {
          e.TypeOfT.IsGenericType.Assert();
          //(e.TypeOfT.Name == "Vec").Assert();
          // go from Vec to IVec
          var Convert = typeof(Ops.ExplicitConvertOperator<,>).MakeGenericType(e.TypeOfT, ToType);
          var mthd = Convert.GetMethod("Make0");
          (mthd != null).Assert();
          return (Expr)mthd.Invoke(null, new object[] { e });
        }


      }


      throw new NotSupportedException();
    }

  }


  [Serializable]
  public struct Vec0<T> : IVec<T, D0> {
    public override string ToString() {
      return VecUtils.ToString(this);
    }
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          default: throw new IndexOutOfRangeException();
        }
      }
    }
  }
  [Serializable]
  public struct Vec1<T> : IVec<T, D1>, IVec<T, Dim<D1, D1>> {
    public T _0;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public static Vec1<T> Default() { return new Vec1<T>(); }

    public override string ToString() { return VecUtils.ToString<T,D1>(this); }
  }
  [Serializable]
  public struct Vec2<T> : IVec<T, D2>, IVec<T, Dim<D1, D2>>, IVec<T, Dim<D2, D1>> {
    public T _0;
    public T _1;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() { return VecUtils.ToString<T,D2>(this); }
  }
  [Serializable]
  public struct Vec3<T> : IVec<T, D3>, IVec<T, Dim<D1, D3>>, IVec<T, Dim<D3, D1>> {
    public T _0;
    public T _1;
    public T _2;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString<T,D3>(this);
    }
  }
  [Serializable]
  public struct Vec4<T> : IVec<T, D4>, IVec<T, Dim<D2, D2>>, IVec<T, Dim<D1, D4>>, IVec<T, Dim<D4, D1>> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString<T,D4>(this);
    }
  }
  [Serializable]
  public struct Vec5<T> : IVec<T, D5> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public T _4;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          case 4: return _4;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString(this);
    }
  }
  [Serializable]
  public struct Vec6<T> : IVec<T, D6>, IVec<T, Dim<D2, D3>>, IVec<T, Dim<D3, D2>> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public T _4;
    public T _5;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          case 4: return _4;
          case 5: return _5;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString<T,D6>(this);
    }
  }
  [Serializable]
  public struct Vec7<T> : IVec<T, D7> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public T _4;
    public T _5;
    public T _6;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          case 4: return _4;
          case 5: return _5;
          case 6: return _6;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString(this);
    }
  }
  [Serializable]
  public struct Vec8<T> : IVec<T, D8>, IVec<T, Dim<D2, D4>>, IVec<T, Dim<D4, D2>> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public T _4;
    public T _5;
    public T _6;
    public T _7;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          case 4: return _4;
          case 5: return _5;
          case 6: return _6;
          case 7: return _7;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString<T,D8>(this);
    }
  }
  [Serializable]
  public struct Vec9<T> : IVec<T, D9>, IVec<T, Dim<D3, D3>> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public T _4;
    public T _5;
    public T _6;
    public T _7;
    public T _8;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          case 4: return _4;
          case 5: return _5;
          case 6: return _6;
          case 7: return _7;
          case 8: return _8;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString<T,D9>(this);
    }
  }
  [Serializable]
  public struct Vec10<T> : IVec<T, D10>, IVec<T, Dim<D2, D5>>, IVec<T, Dim<D5, D2>> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public T _4;
    public T _5;
    public T _6;
    public T _7;
    public T _8;
    public T _9;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          case 4: return _4;
          case 5: return _5;
          case 6: return _6;
          case 7: return _7;
          case 8: return _8;
          case 9: return _9;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString<T,D10>(this);
    }
  }
  [Serializable]
  public struct Vec11<T> : IVec<T, D11> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public T _4;
    public T _5;
    public T _6;
    public T _7;
    public T _8;
    public T _9;
    public T _10;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          case 4: return _4;
          case 5: return _5;
          case 6: return _6;
          case 7: return _7;
          case 8: return _8;
          case 9: return _9;
          case 10: return _10;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString(this);
    }
  }
  [Serializable]
  public struct Vec12<T> : IVec<T, D12>, IVec<T, Dim<D2, D6>>, IVec<T, Dim<D6, D2>>, IVec<T, Dim<D3, D4>>, IVec<T, Dim<D4, D3>> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public T _4;
    public T _5;
    public T _6;
    public T _7;
    public T _8;
    public T _9;
    public T _10;
    public T _11;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          case 4: return _4;
          case 5: return _5;
          case 6: return _6;
          case 7: return _7;
          case 8: return _8;
          case 9: return _9;
          case 10: return _10;
          case 11: return _11;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString<T,D12>(this);
    }
  }
  [Serializable]
  public struct Vec13<T> : IVec<T, D13> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public T _4;
    public T _5;
    public T _6;
    public T _7;
    public T _8;
    public T _9;
    public T _10;
    public T _11;
    public T _12;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          case 4: return _4;
          case 5: return _5;
          case 6: return _6;
          case 7: return _7;
          case 8: return _8;
          case 9: return _9;
          case 10: return _10;
          case 11: return _11;
          case 12: return _12;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString(this);
    }
  }
  [Serializable]
  public struct Vec14<T> : IVec<T, D14>, IVec<T, Dim<D2, D7>>, IVec<T, Dim<D7, D2>> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public T _4;
    public T _5;
    public T _6;
    public T _7;
    public T _8;
    public T _9;
    public T _10;
    public T _11;
    public T _12;
    public T _13;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          case 4: return _4;
          case 5: return _5;
          case 6: return _6;
          case 7: return _7;
          case 8: return _8;
          case 9: return _9;
          case 10: return _10;
          case 11: return _11;
          case 12: return _12;
          case 13: return _13;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString<T,D14>(this);
    }
  }
  [Serializable]
  public struct Vec15<T> : IVec<T, D15>, IVec<T, Dim<D3, D5>>, IVec<T, Dim<D5, D3>> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public T _4;
    public T _5;
    public T _6;
    public T _7;
    public T _8;
    public T _9;
    public T _10;
    public T _11;
    public T _12;
    public T _13;
    public T _14;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          case 4: return _4;
          case 5: return _5;
          case 6: return _6;
          case 7: return _7;
          case 8: return _8;
          case 9: return _9;
          case 10: return _10;
          case 11: return _11;
          case 12: return _12;
          case 13: return _13;
          case 14: return _14;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString<T,D15>(this);
    }
  }
  [Serializable]
  public struct Vec16<T> : IVec<T, D16>, IVec<T, Dim<D4, D4>>, IVec<T, Dim<D2, D8>>, IVec<T, Dim<D8, D2>> {
    public T _0;
    public T _1;
    public T _2;
    public T _3;
    public T _4;
    public T _5;
    public T _6;
    public T _7;
    public T _8;
    public T _9;
    public T _10;
    public T _11;
    public T _12;
    public T _13;
    public T _14;
    public T _15;
    public object BaseGet(int Idx) { return this[Idx]; }
    public T this[int Idx] {
      get {
        switch (Idx) {
          case 0: return _0;
          case 1: return _1;
          case 2: return _2;
          case 3: return _3;
          case 4: return _4;
          case 5: return _5;
          case 6: return _6;
          case 7: return _7;
          case 8: return _8;
          case 9: return _9;
          case 10: return _10;
          case 11: return _11;
          case 12: return _12;
          case 13: return _13;
          case 14: return _14;
          case 15: return _15;
          default: throw new IndexOutOfRangeException();
        }
      }
    }
    public override string ToString() {
      return VecUtils.ToString<T,D16>(this);
    }
  }

}

namespace Bling.Vecs {
  using Bling.Core;
  using Bling.Ops;
  using Bling.Matrices;
  public interface IVecEval<EVAL> : IEval<EVAL> where EVAL : Eval<EVAL> {
    Eval<EVAL>.Info<T> Access<T, D>(Eval<EVAL>.Info<IVec<T, D>> Vec, Eval<EVAL>.Info<int> Index) where D : Dim<D>;

    Eval<EVAL>.Info<T> Access<T, D>(Eval<EVAL>.Info<IVec<T, D>> Vec, int Index) where D : Dim<D>;

    Eval<EVAL>.Info<IVec<T,D>> Composite<T, D>(Expr<T>[] Expr, Eval<EVAL>.Info<T>[] Es) where D : Dim<D>;
  }
  public interface IMatrixEval<EVAL> : IVecEval<EVAL> where EVAL : Eval<EVAL> {
    Eval<EVAL>.Info<T> Access<T, D>(Eval<EVAL>.Info<IVec<T, D>> Vec, int row, int col) where D : Dim2D<D>;
    Eval<EVAL>.Info<T> Access<T, D>(Eval<EVAL>.Info<IVec<T, D>> Vec, Eval<EVAL>.Info<int> m, Eval<EVAL>.Info<int> n) where D : Dim2D<D>;
  }
  public abstract class BaseAccessExpr<T, D> : Expr<T> where D : Dim<D> {
    public readonly Expr<IVec<T, D>> Vector;
    static BaseAccessExpr() {
      (Dim<D>.Count >= 1).Assert();
    }

    public BaseAccessExpr(Expr<IVec<T, D>> Vector) {
      this.Vector = Vector; ;
    }
    protected override int GetHashCode0() {
      return Vector.GetHashCode();
    }
    protected override bool Equals0(Expr<T> e) {
      if (!(e is BaseAccessExpr<T, D>)) return false;
      return Vector.Equals(((BaseAccessExpr<T, D>)e).Vector);
    }
    protected override string ToString1() {
      return Vector.ToString();
    }
    public override bool Solve(IAssign P, Expr<T> other) {
      if (typeof(D) == typeof(D1)) {
        // push it to vector.

        return Vector.Solve(P, Composite<T, D>.Make(other));
      }

      return base.Solve(P, other);
    }
  }
  public partial class AccessExpr<T, D> : BaseAccessExpr<T,D> where D : Dim<D> {
    public readonly Expr<int> Index;
    private AccessExpr(Expr<IVec<T, D>> Vector, Expr<int> Index) : base(Vector) { this.Index = Index; }

    public override Expr Cheap {
      get {
        if (Index.IsConstant) return Vector.Cheap;
        else if (Vector.IsConstant) return Index.Cheap;
        else return base.Cheap;
      }
    }

    public override bool IsConstant {
      get {
        return Vector.IsConstant && Index.IsConstant;
      }
    }
    public override bool IsObviousConstant {
      get {
        return Vector.IsObviousConstant && Index.IsObviousConstant;
      }
    }
    public override T CurrentValue {
      get {
        if (IsObviousConstant) {
          return Vector.CurrentValue[Index.CurrentValue];
        } else return base.CurrentValue;
      }
    }

    protected override int GetHashCode0() {
      return base.GetHashCode0() + Index.GetHashCode();
    }
    public static Expr<T> Make(Expr<IVec<T, D>> Vector, int Index) {
      if (Vector.IsObviousConstant) {
        return new Constant<T>(Vector.CurrentValue[Index]);
      }
      return Make(Vector, new Constant<int>(Index));
    }
    public static Expr<T> Make(Expr<IVec<T, D>> Vector, Expr<int> Index) {
      if (Vector is Composite<T, D> && Dim<D>.Count == 1) { // don't skip other composites.
        return ((Composite<T, D>)Vector).Components[0];
      }
      if (Vector is Composite<T, D> && Index.IsObviousConstant) {
        return ((Composite<T, D>)Vector).Components[Index.CurrentValue];
      }
      if (Vector.IsObviousConstant && Index.IsObviousConstant) {
        return new Constant<T>(Vector.CurrentValue[Index.CurrentValue]);
      }
      return new AccessExpr<T, D>(Vector, Index);
    }
    protected override bool Equals0(Expr<T> e) {
      if (!base.Equals0(e)) return false;
      if (!(e is AccessExpr<T, D>)) return false;
      return Index.Equals(((AccessExpr<T, D>)e).Index);
    }
    protected override string ToString1() {
      if (Dim<D>.Count == 1) return base.ToString1();
      else return base.ToString1() + "[" + Index + "]";
    }
    protected override Eval<EVAL>.Info<T> Eval<EVAL>(Eval<EVAL> txt) {
      if (txt is IVecEval<EVAL>) {
        var Vector0 = txt.DoEval(Vector);
        if (Index.IsObviousConstant) {
          return ((IVecEval<EVAL>)txt).Access(Vector0, Index.CurrentValue);
        } else return ((IVecEval<EVAL>)txt).Access(Vector0, txt.DoEval(Index));
      } else if (txt is TranslateEval<EVAL>) {
        var e1 = ((TranslateEval<EVAL>)txt).Translate(Vector);
        var e2 = ((TranslateEval<EVAL>)txt).Translate(Index);
        return ((TranslateEval<EVAL>)txt).NoTranslation(new AccessExpr<T, D>(e1, e2));
      }
      throw new NotImplementedException();
    }
  }
  public partial class Access2DExpr<T, D> : BaseAccessExpr<T, D>
    where D : Dim2D<D> {
    protected readonly Expr<int> IndexRow;
    protected readonly Expr<int> IndexCol;
    private Access2DExpr(Expr<IVec<T, D>> Vector, Expr<int> IndexRow, Expr<int> IndexCol) : base(Vector) {
      this.IndexRow = IndexRow;
      this.IndexCol = IndexCol;
    }

    public override Expr Cheap {
      get {
        if (Vector.IsConstant) {
          if (IndexRow.IsConstant) return IndexCol.Cheap;
          if (IndexCol.IsConstant) return IndexRow.Cheap;
        } else if (IndexRow.IsConstant) {
          if (IndexCol.IsConstant) return Vector.Cheap;
        } 
        return base.Cheap;
      }
    }
    public override T CurrentValue {
      get {
        if (IsObviousConstant) {
          return Vector.CurrentValue[IndexRow.CurrentValue * Dim2D<D>.ColCount + IndexCol.CurrentValue];
        } else return base.CurrentValue;
      }
    }

    public static Expr<T> Make(Expr<IVec<T, D>> Vector, Expr<int> IndexRow, Expr<int> IndexCol) {
      if (IndexRow.IsObviousConstant && IndexCol.IsObviousConstant) {
        if (Vector is Composite<T, D>) {
          var Vector0 = (Composite<T, D>)Vector;
          return Vector0[IndexRow.CurrentValue * Dim2D<D>.ColCount + IndexCol.CurrentValue];
        } else if (Vector.IsObviousConstant) {
          var Vector0 = Vector.CurrentValue;
          return new Constant<T>(Vector0[IndexRow.CurrentValue * Dim2D<D>.ColCount + IndexCol.CurrentValue]);
        }
      }
      return new Access2DExpr<T, D>(Vector, IndexRow, IndexCol);
    }
    protected override string ToString1() {
      if (Dim<D>.Count == 1) return base.ToString1();
      else return base.ToString1() + "[" + IndexRow + ", " + IndexCol + "]";
    }
    protected override int GetHashCode0() {
      return base.GetHashCode0() + IndexRow.GetHashCode() + IndexCol.GetHashCode();
    }
    protected override bool Equals0(Expr<T> e) {
      if (!base.Equals0(e)) return false;
      if (!(e is Access2DExpr<T, D>)) return false;
      return IndexRow.Equals(((Access2DExpr<T, D>)e).IndexRow) && 
             IndexCol.Equals(((Access2DExpr<T, D>)e).IndexCol);
    }
    protected override Eval<EVAL>.Info<T> Eval<EVAL>(Eval<EVAL> txt) {
      if (txt is IMatrixEval<EVAL>) {
        if (IndexRow.IsObviousConstant && IndexCol.IsObviousConstant)
          return ((IMatrixEval<EVAL>)txt).Access(txt.DoEval(Vector), IndexRow.CurrentValue, IndexCol.CurrentValue);
        else return ((IMatrixEval<EVAL>)txt).Access(txt.DoEval(Vector), txt.DoEval(IndexRow), txt.DoEval(IndexCol));
      } else if (txt is IVecEval<EVAL>) {
        if (IndexRow.IsConstant && IndexCol.IsConstant)
          return ((IVecEval<EVAL>)txt).Access(txt.DoEval(Vector), IndexRow.CurrentValue * Dim2D<D>.ColCount + IndexCol.CurrentValue);
        else return ((IVecEval<EVAL>)txt).Access(txt.DoEval(Vector), txt.DoEval((IndexRow.Bl() * Dim2D<D>.ColCount + IndexCol.Bl()).Provider));
      } else if (txt is TranslateEval<EVAL>) {
        var e1 = ((TranslateEval<EVAL>)txt).Translate(Vector);
        var e2 = ((TranslateEval<EVAL>)txt).Translate(IndexRow);
        var e3 = ((TranslateEval<EVAL>)txt).Translate(IndexCol);
        return ((TranslateEval<EVAL>)txt).NoTranslation(new Access2DExpr<T, D>(e1,e2,e3));
      }
      throw new NotImplementedException();
    }
  }
  // matrix or vector.
  public partial class Composite<T, D> : Expr<IVec<T, D>> where D : Dim<D> {
    internal readonly Expr<T>[] Components;
    private Composite(params Expr<T>[] Es) {
      this.Components = Es;
    }
    public override Expr Cheap {
      get {
        Expr NonConstant = null;
        for (int i = 0; i < Components.Length; i++) {
          if (Components[i].IsConstant) continue;
          else if (NonConstant != null) return base.Cheap;
          else NonConstant = Components[i];
        }
        if (NonConstant != null) return NonConstant.Cheap;
        else return base.Cheap;
      }
    }


    public override bool IsConstant {
      get {
        var b = true;
        foreach (var c in Components) b = b && c.IsConstant;
        return b;
      }
    }
    public override bool IsObviousConstant {
      get {
        var b = true;
        foreach (var c in Components) b = b && c.IsObviousConstant;
        return b;
      }
    }
    public override IVec<T, D> CurrentValue {
      get {
        if (IsObviousConstant) {
          var values = new T[Dim<D>.Count];
          for (int i = 0; i < Dim<D>.Count; i++) values[i] = Components[i].CurrentValue;
          // need to return the right...
          return VecUtils.Create<T,D>(values);

        } else return base.CurrentValue;
      }
    }

    public static Expr<IVec<T, D>> Make(params Expr<T>[] Es) {
      (Es.Length == Dim<D>.Count).Assert();
      // a common case to get rid of extra accesses.
      if (Es.Length == 1 && Es[0] is BaseAccessExpr<T, D>) {
        var access = (BaseAccessExpr<T, D>)Es[0];
        return access.Vector;
      }
      return new Composite<T,D>(Es);
    }
    protected override int GetHashCode0() {
      var hc = 0;
      foreach (var e in Components) hc += e.GetHashCode();
      return hc;
    }
    protected override bool Equals0(Expr<IVec<T, D>> e) {
      if (!(e is Composite<T, D>)) return false;
      for (int i = 0; i < Dim<D>.Count; i++)
        if (!Components[i].Equals(((Composite<T, D>)e).Components[i])) return false;
      return true;
    }
    protected override string ToString1() {
      if (Dim<D>.Count == 1) return Components[0].ToString();
      var str = "[";
      for (int i = 0; i < Dim<D>.Count; i++) {
        if (i > 0) str += ", ";
        str += Components[i].ToString();
      }
      return str + "]";
    }
    public Expr<T> this[int Idx] { get { return Components[Idx]; } }
    protected override Eval<EVAL>.Info<IVec<T, D>> Eval<EVAL>(Eval<EVAL> txt) {
      var memo = txt.Memo<IVec<T, D>>(this);
      if (memo != null) return memo;

      if (txt is IVecEval<EVAL>) {
        var Es = new Eval<EVAL>.Info<T>[Dim<D>.Count];
        for (int i = 0; i < Dim<D>.Count; i++)
          Es[i] = txt.DoEval(Components[i]);

        return txt.Memo<IVec<T, D>>(this, () => 
          ((IVecEval<EVAL>)txt).Composite<T, D>(Components, Es), Es);
      } else if (txt is TranslateEval<EVAL>) {
        var Components0 = new Expr<T>[Components.Length];
        for (int i = 0; i < Components.Length; i++)
          Components0[i] = ((TranslateEval<EVAL>)txt).Translate(Components[i]);
        return ((TranslateEval<EVAL>)txt).NoTranslation(new Composite<T,D>(Components0));
      }
      throw new NotImplementedException();
    }
    public override bool Solve(IAssign P, Expr<IVec<T,D>> other) {
      var b = true;
      for (int i = 0; i < Dim<D>.Count; i++)
        b = b && Components[i].Solve(P, AccessExpr<T,D>.Make(other, i));
      return b;
    }

  }

  public static partial class VecMatrix<D> where D : Dim1D<D> {

    public partial class FromMatrixA : Ops.Operator<IVec<double, Dim<D1, D>>, IVec<double, D>, FromMatrixA> {
      public new static readonly FromMatrixA Instance = new FromMatrixA();
      private FromMatrixA() { }

      public override Func<SmartString, SmartString> Shader<EVAL>(Bling.Shaders.BaseShaderEval<EVAL> txt, Operation<IVec<double, Dim<D1, D>>, IVec<double, D>> op) {
        var to = txt.TypeNameFor(typeof(IVec<double, Dim<D1,D>>)); // be explicit. 
        var from = txt.TypeNameFor(typeof(IVec<double, D>)); // be explicit.
        if (to.Equals(from)) return a => a;
        else return a => "((" + from + ")" + a + ")";
      }
      public override SmartString Format(SmartString s) {
        return "matrix(" + s + ")";
      }
      public override Expr<IVec<double, D>> Expand(Expr<IVec<double, Dim<D1, D>>> argA) {
        DoubleBl[] Es = new DoubleBl[Dim<D>.Count];
        for (int i = 0; i < Dim<D>.Count; i++) Es[i] = new MatrixBl<D1, D>(argA)[0, i];
        return new FlexDoubleBl<D>(Es);
      }
    }
    public partial class FromMatrixB : Ops.Operator<IVec<double, Dim<D, D1>>, IVec<double, D>, FromMatrixB> {
      public new static readonly FromMatrixB Instance = new FromMatrixB();
      private FromMatrixB() { }

      public override Func<SmartString, SmartString> Shader<EVAL>(Bling.Shaders.BaseShaderEval<EVAL> txt, Operation<IVec<double, Dim<D, D1>>, IVec<double, D>> op) {
        var to = txt.TypeNameFor(typeof(IVec<double, Dim<D, D1>>)); // be explicit. 
        var from = txt.TypeNameFor(typeof(IVec<double, D>)); // be explicit.
        if (to.Equals(from)) return a => a;
        else return a => "((" + from + ")" + a + ")";
      }
      public override SmartString Format(SmartString s) {
        return "matrix(" + s + ")";
      }
      public override Expr<IVec<double, D>> Expand(Expr<IVec<double, Dim<D, D1>>> argA) {
        DoubleBl[] Es = new DoubleBl[Dim<D>.Count];
        for (int i = 0; i < Dim<D>.Count; i++) Es[i] = new MatrixBl<D, D1>(argA)[0, i];
        return new FlexDoubleBl<D>(Es);
      }
    }
    public partial class FromVecA : Ops.Operator<IVec<double, D>, IVec<double, Dim<D1, D>>, FromVecA> {
      public new static readonly FromVecA Instance = new FromVecA();
      private FromVecA() { }
      public override Func<SmartString, SmartString> Shader<EVAL>(Bling.Shaders.BaseShaderEval<EVAL> txt, Operation<IVec<double, D>, IVec<double, Dim<D1, D>>> op) {
        var to = txt.TypeNameFor(typeof(IVec<double, Dim<D1, D>>)); // be explicit.
        var from = txt.TypeNameFor(typeof(IVec<double, D>)); // be explicit.
        if (to.Equals(from)) return a => a;
        else return a => "((" + to + ")" + a + ")";
      }
      public override SmartString Format(SmartString s) {
        return "vec(" + s + ")";
      }
      public override Expr<IVec<double, Dim<D1, D>>> Expand(Expr<IVec<double, D>> argA) {
        DoubleBl[] Es = new DoubleBl[Dim<D>.Count];
        for (int i = 0; i < Dim<D>.Count; i++) Es[i] = new FlexDoubleBl<D>(argA)[i];
        return new MatrixBl<D1,D>(Es);
      }
    }
    public partial class FromVecB : Ops.Operator<IVec<double, D>, IVec<double, Dim<D,D1>>, FromVecB> {
      public new static readonly FromVecB Instance = new FromVecB();
      private FromVecB() { }
      public override Func<SmartString, SmartString> Shader<EVAL>(Bling.Shaders.BaseShaderEval<EVAL> txt, Operation<IVec<double, D>, IVec<double, Dim<D, D1>>> op) {
        var to = txt.TypeNameFor(typeof(IVec<double, Dim<D, D1>>)); // be explicit. 
        var from = txt.TypeNameFor(typeof(IVec<double, D>)); // be explicit.
        if (to.Equals(from)) return a => a;
        else return a => "((" + to + ")" + a + ")";
      }
      public override SmartString Format(SmartString s) {
        return "vec(" + s + ")";
      }
      public override Expr<IVec<double, Dim<D,D1>>> Expand(Expr<IVec<double, D>> argA) {
        DoubleBl[] Es = new DoubleBl[Dim<D>.Count];
        for (int i = 0; i < Dim<D>.Count; i++) Es[i] = new FlexDoubleBl<D>(argA)[i];
        return new MatrixBl<D,D1>(Es);
      }
    }

  }
}

namespace Bling.Vecs {
  using System.Reflection.Emit;
  using System.Reflection;
  using linq = Microsoft.Linq.Expressions;

  static class NewVec {
    internal static readonly ModuleBuilder Module;
    static NewVec() {
      AppDomain Domain = System.Threading.Thread.GetDomain();
      AssemblyBuilder AsmBuilder = Domain.DefineDynamicAssembly(new AssemblyName() { Name = "Vecs" }, AssemblyBuilderAccess.RunAndSave);
      Module = AsmBuilder.DefineDynamicModule("VecsModule", true);
    }
  }
  public static class Vecs<D> where D : Dim<D> {
    private static Type VecType0;
    public static Type VecType {
      get {
        if (VecType0 != null) return VecType0;
        TypeBuilder Bld = NewVec.Module.DefineType(Dim<D>.Name, TypeAttributes.Public |
            TypeAttributes.Sealed | TypeAttributes.SequentialLayout |
            TypeAttributes.Serializable, typeof(ValueType));
        var T = Bld.DefineGenericParameters("T")[0];
        Bld.AddInterfaceImplementation(typeof(IVec<,>).MakeGenericType(T, typeof(D)));
        Bld.DefineDefaultConstructor(MethodAttributes.Public);
        // add fields
        for (int i = 0; i < Dim<D>.Count; i++) {
          var fld = Bld.DefineField("_" + i, T, FieldAttributes.Public);
        }
        VecType0 = Bld;
        return VecType0;
      }
    }
  }
  public static class Matrix<T, D> where D : Dim2D<D> {
    public static IVec<T, D> New(params T[][] values) {
      var t = new T[Dim<D>.Count];
      (values.Length == Dim2D<D>.RowCount).Assert();
      for (int i = 0; i < Dim2D<D>.RowCount; i++) {
        (values[i].Length == Dim2D<D>.ColCount).Assert();
        for (int j = 0; j < Dim2D<D>.ColCount; j++) {
          t[i * Dim2D<D>.ColCount + j] = values[i][j];
        }
      }
      return Vecs<T, D>.New(t);
    }

  }

  public static class Vecs<T,D> where D : Dim<D> {
    private static Func<T[], IVec<T, D>> FactoryB;
    private static readonly Func<IVec<T, D>, T>[] Access0 = new Func<IVec<T, D>, T>[Dim<D>.Count];
    private static object Access1;

    public static Type AccessDelegateType {
      get {
        var Type = Vecs<D>.VecType.MakeGenericType(typeof(T));
        var DelegateType = typeof(System.Func<,,>).MakeGenericType(Type, typeof(int), typeof(T));
        return DelegateType;
      }
    }
    public static object Access() {
      if (Access1 != null) return Access1;
      var Type = Vecs<D>.VecType.MakeGenericType(typeof(T));
      var vec = linq.Expression.Parameter(Type, "vec");
      var index = linq.Expression.Parameter(typeof(int), "index");
      linq.Expression e = vec;
      var cases = new linq.SwitchCase[Dim<D>.Count];
      for (int i = 0; i < Dim<D>.Count; i++)
        cases[i] = linq.Expression.SwitchCase(linq.Expression.Field(e, "_" + i), linq.Expression.Constant(i, typeof(int)));

      e = linq.Expression.Switch(typeof(T), index, linq.Expression.Constant(default(T)), null, cases);
      var DelegateType = AccessDelegateType;
      var lambda = linq.Expression.Lambda(DelegateType, e, vec, index);
      var f = lambda.Compile();
      Access1 = f;
      return Access1;
    }
    public static linq.Expression Access(linq.Expression Vec, int i) {
      linq.Expression e = Vec;
      e = linq.Expression.Field(e, "_" + i);
      return e;
    }
    public static T Access(IVec<T, D> V, int i) {
      if (Access0[i] != null) return Access0[i](V);
      var vec = linq.Expression.Parameter(typeof(IVec<T, D>), "vec");
      linq.Expression e = linq.Expression.Convert(vec, Vecs<D>.VecType.MakeGenericType(typeof(T)));
      e = linq.Expression.Field(e, "_" + i);
      var f = linq.Expression.Lambda<System.Func<IVec<T, D>, T>>(e, vec).Compile();
      Access0[i] = vec0 => f(vec0);
      return Access0[i](V);
    }

    public static linq.Expression New(params linq.Expression[] Args) {
      (Dim<D>.Count == Args.Length).Assert();
      return linq.Expression.Invoke(linq.Expression.Constant(New0), Args);
    }
    public static Func<T[], IVec<T, D>> New0 {
      get {
        if (FactoryB != null) return FactoryB;
        var Type = Vecs<D>.VecType.MakeGenericType(typeof(T));
        var Exprs = new linq.Expression[Dim<D>.Count + 2];
        var temp = linq.Expression.Parameter(Type, "vec");
        var args = linq.Expression.Parameter(Type.MakeArrayType(), "args");
        Exprs[0] = linq.Expression.Assign(temp, linq.Expression.New(Type));
        for (int i = 0; i < Dim<D>.Count; i++)
          Exprs[i + 1] = linq.Expression.Assign(
            linq.Expression.Field(temp, "_" + i),
            linq.Expression.ArrayAccess(args, linq.Expression.Constant(i, typeof(int))));
        Exprs[Dim<D>.Count + 1] = temp;

        var block = linq.Expression.Block(Type, new linq.ParameterExpression[] { temp }, Exprs);
        var lambda = linq.Expression.Lambda<System.Func<T[], IVec<T, D>>>(block, args);
        var f0 = lambda.Compile();
        FactoryB = Ts => f0(Ts);
        return FactoryB;
      }
    }
    public static IVec<T, D> New(params T[] Args) {
      (Dim<D>.Count == Args.Length).Assert();
      return New0(Args);
    }
  }

}
